/**********************************************************************************************************************
 * @file    icm42670.h
 * @author  Queclink Billy.Luo
 * @date    2021-5-31
 * @brief   ICM42670驱动程序头文件
 *
 * Copyright (C) 2021 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 *********************************************************************************************************************/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ICM42670_H__
#define __ICM42670_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
    
typedef int32_t (*icm42670_write_t)(uint8_t reg, uint8_t *data, uint16_t cnt);
typedef int32_t (*icm42670_read_t)(uint8_t reg, uint8_t *data, uint16_t cnt);
typedef void (*icm42670_delay_t)(unsigned int ms);

typedef struct {
    unsigned char       chip_id;
    icm42670_write_t    write_reg;
    icm42670_read_t     read_reg;
    icm42670_delay_t    delay_ms;
} context_t;

typedef struct {
    uint8_t bit0 :1;
    uint8_t bit1 :1;
    uint8_t bit2 :1;
    uint8_t bit3 :1;
    uint8_t bit4 :1;
    uint8_t bit5 :1;
    uint8_t bit6 :1;
    uint8_t bit7 :1;
} bitwise_t;

#define ICM_ENABLE        1
#define ICM_DISABLE       0

int32_t icm42670_reg_set(context_t *ctx, uint8_t reg, uint8_t val);
int32_t icm42670_reg_get(context_t *ctx, uint8_t reg, uint8_t *val);

/* BANK0 REGISTER */

#define SIGNAL_PATH_REG     0x02
typedef struct {
    uint8_t unused1     :2;
    uint8_t fifo_flush  :1;
    uint8_t unused2     :1;
    uint8_t soft_reset  :1;
    uint8_t unused3     :3;
} signal_path_t;

#define INT_CONFIG_REG      0x06
typedef struct {
    uint8_t int1_polarity   :1;
    uint8_t int1_circuit    :1;
    uint8_t int1_mode       :1;
    uint8_t int2_polarity   :1;
    uint8_t int2_circuit    :1;
    uint8_t int2_mode       :1;
    uint8_t unused          :2;
} int_conf_t;

enum {
    ACTIVE_LOW  = 0,
    ACTIVE_HIGH = 1,
};

enum {
    OPEN_DRAIN  = 0,
    PUSH_PULL   = 1,
};

enum {
    PULSE_MODE  = 0,
    LATCH_MODE  = 1,
};

#define TEMP_DATAH_REG      0x09
#define TEMP_DATAL_REG      0x0A
float icm42670_temperature_get(context_t *ctx);

#define ACCEL_DATA_XH_REG   0x0B
int32_t icm42670_accel_raw_get(context_t *ctx, uint8_t *buff);

#define GYRO_DATA_XH_REG    0x11
int32_t icm42670_gyro_raw_get(context_t *ctx, uint8_t *buff);

#define PWR_MGMT0_REG       0x1F
typedef struct {
    uint8_t acc_mode    :2;
    uint8_t gyro_mode   :2;
    uint8_t idle        :1;
    uint8_t unused      :2;
    uint8_t lp_clk_sel  :1;    
} pwr_mgmt0_t;

enum {
    GYRO_MODE_OFF = 0,
    GYRO_MODE_STANDBY,
    GYRO_MODE_LN = 3
};

enum {
    ACC_MODE_OFF = 0,
    ACC_MODE_LP = 2,
    ACC_MODE_LN
};

#define GYRO_CONFIG0_REG    0x20
#define ACCEL_CONFIG0_REG   0x21
typedef struct {
    uint8_t odr         :4;
    uint8_t unsued1     :1;
    uint8_t range       :2;
    uint8_t unsued2     :1;
} odr_range_t;

enum {
    GYRO_RANGE_2000DPS = 0,
    GYRO_RANGE_1000DPS,
    GYRO_RANGE_500DPS,
    GYRO_RANGE_250DPS,
};

enum {
    ACCEL_RANGE_16G = 0,
    ACCEL_RANGE_8G,
    ACCEL_RANGE_4G,
    ACCEL_RANGE_2G
};

enum {
    ODR_1600HZ = 5,
    ODR_800HZ,
    ODR_400HZ,
    ODR_200HZ,
    ODR_100HZ,
    ODR_50HZ,
};

#define APEX_CONFIG0_REG    0x25
typedef struct {
    uint8_t mem_reset   :1;
    uint8_t unsued1     :1;
    uint8_t dmp_init    :1;
    uint8_t power_save  :1;
    uint8_t unsued2     :4;
} apex_conf0_t;

#define APEX_CONFIG1_REG    0x26
typedef struct {
    uint8_t dmp_odr     :2;
    uint8_t unused1     :1;
    uint8_t ped_en      :1;
    uint8_t tilt_en     :1;
    uint8_t ff_en       :1;
    uint8_t smd_en      :1;
    uint8_t unused2     :1;
} apex_conf1_t;

enum {
    DMP_ODR_25HZ = 0,
    DMP_ODR_400HZ,
    DMP_ODR_50HZ,
    DMP_ODR_100HZ
};

#define WOM_CONFIG_REG      0x27
typedef struct {
    uint8_t wom_en      :1;
    uint8_t wom_mode    :1;
    uint8_t int_mode    :1;
    uint8_t int_dur     :2;
    uint8_t unsued      :3;
} wom_conf_t;

enum {
    CMP_TO_INIT = 0,
    CMP_TO_PREV
};

enum {
    LOGIC_OR = 0,
    LOGIC_AND
};

#define FIFO_CONFIG1_REG    0x28
typedef struct {
    uint8_t fifo_bypass :1;
    uint8_t fifo_mode   :1;
    uint8_t unsued      :6;
} fifo_conf1_t;

enum {
    STREAM_MODE = 0,
    STOP_ON_FULL,
};

#define FIFO_CONFIG2_REG    0x29
#define FIFO_CONFIG3_REG    0x2A
int32_t icm42670_fifo_wm_level_set(context_t *ctx, uint16_t level);

#define INT_SRC0_REG        0x2B
typedef struct {
    uint8_t agc_rdy_int1    :1;
    uint8_t fifo_full_int1  :1;
    uint8_t fifo_wm_int1    :1;
    uint8_t new_data_int1   :1;
    uint8_t reset_done_int1 :1;
    uint8_t pll_rdy_int1    :1;
    uint8_t fsync_int1      :1;
    uint8_t self_test_int1  :1;
} int_src0_t;

#define INT_SRC1_REG        0x2C
typedef struct {
    uint8_t wom_x_int1      :1;
    uint8_t wom_y_int1      :1;
    uint8_t wom_z_int1      :1;
    uint8_t smd_int1        :1;
    uint8_t unused          :4;
} int_src1_t;

#define INT_SRC3_REG        0x2D
typedef struct {
    uint8_t agc_rdy_int2    :1;
    uint8_t fifo_full_int2  :1;
    uint8_t fifo_wm_int2    :1;
    uint8_t new_data_int2   :1;
    uint8_t reset_done_int2 :1;
    uint8_t pll_rdy_int2    :1;
    uint8_t fsync_int2      :1;
    uint8_t self_test_int1  :1;
} int_src3_t;

#define INT_SRC4_REG        0x2E
typedef struct {
    uint8_t wom_x_int2      :1;
    uint8_t wom_y_int2      :1;
    uint8_t wom_z_int2      :1;
    uint8_t smd_int2        :1;
    uint8_t unused          :4;
} int_src4_t;

#define INTF_CONFIG0_REG    0x35
typedef struct {
    uint8_t unsued1     :4;
    uint8_t data_endian :1;
    uint8_t fifo_endian :1;
    uint8_t fifo_record :1;
    uint8_t unsued2     :1;
} intf_conf0_t;

enum {
    LITTLE_ENDIAN = 0,
    BIG_ENDIAN
};

enum {
    FIFO_CNT_BYTE = 0,
    FIFO_CNT_RECORD
};

#define INT_STATUS_REG      0x3A
typedef struct {
    uint8_t agc_rdy     :1;
    uint8_t fifo_full   :1;
    uint8_t fifo_wm     :1;
    uint8_t unused      :1;
    uint8_t reset_done  :1;
    uint8_t pll_ready   :1;
    uint8_t ui_fsync    :1;
    uint8_t self_test   :1;    
} int_status_t;

#define INT_STATUS2_REG     0x3B
typedef struct {
    uint8_t wom_z       :1;
    uint8_t wom_y       :1;
    uint8_t wom_x       :1;
    uint8_t smd         :1;
    uint8_t unsued      :4;
} int_status2_t;

#define INT_STATUS3_REG     0x3C
typedef struct {
    uint8_t unsued1     :1;
    uint8_t low_g       :1;
    uint8_t ff          :1;
    uint8_t tilt        :1;
    uint8_t step_cnt    :1;
    uint8_t step_det    :1;
    uint8_t unsued      :2;
} int_status3_t;

#define FIFO_COUNTH_REG     0x3D
#define FIFO_COUNTL_REG     0x3E
int32_t icm42670_fifo_data_cnt_get(context_t *ctx, uint16_t *cnt);

#define FIFO_DATA_REG       0x3F
int32_t icm42670_fifo_packet_data_read(context_t *ctx, uint8_t buff[16]);

#define CHIP_ID_REG         0x75

#define BANK_SEL_W          0x79
#define MADDR_W             0x7A
#define MDATA_W             0x7B

enum {
    ICM_BANK1,
    ICM_BANK2,
    ICM_BANK3
};

int32_t bank_reg_set(context_t *ctx, uint8_t bank, uint8_t reg, uint8_t data);

/* BANK1 REGISTER */
#define TMST_CONFIG1_REG    0x00
typedef struct {
    uint8_t tmst_en         :1;
    uint8_t fsync_en        :1;
    uint8_t delta_en        :1;
    uint8_t resolution      :1;
    uint8_t on_sreg_en      :1;
    uint8_t unused          :3;
} tmst_conf1_t;

#define FIFO_CONFIG5_REG    0x01
typedef struct {
    uint8_t fifo_acc_en     :1;
    uint8_t fifo_gyro_en    :1;
    uint8_t tmst_fsync_en   :1;
    uint8_t fifo_20bit_en   :1;
    uint8_t partial_rd      :1;
    uint8_t wm_gt_th        :1;
    uint8_t unsued          :2;
} fifo_conf5_t;

#define INT_SRC6_REG        0x2F
typedef struct {
    uint8_t unused          :3;
    uint8_t tilt_int1       :1;
    uint8_t step_cnt_int1   :1;
    uint8_t step_det_int1   :1;
    uint8_t lowg_int1       :1;
    uint8_t ff_int1         :1;
} int_src6_t;

#define INT_SRC7_REG        0x30
typedef struct {
    uint8_t unused          :3;
    uint8_t tilt_int2       :1;
    uint8_t step_cnt_int2   :1;
    uint8_t step_det_int2   :1;
    uint8_t lowg_int2       :1;
    uint8_t ff_int2         :1;
} int_src7_t;

#define APEX_CONFIG10_REG   0x49
typedef struct {
    uint8_t lowg_time   :3;
    uint8_t lowg_thold  :5;
} lowg_conf_t;


#define WOMX_THR_REG       			0x4B
#define WOMY_THR_REG        		0x4C
#define WOMZ_THR_REG        		0x4D

#define BLK_SEL_W_REG        		0x79
typedef struct {
    uint8_t blk_sel_w;
} blk_sel_w_t;

#define MADDR_W_REG        			0x7A
typedef struct {
    uint8_t maadr_w;
} maadr_w_t;

#define M_W_REG        				0x7B
typedef struct {
    uint8_t m_w;
} m_w_t;


typedef union {
    signal_path_t       signal_path;
    int_conf_t          int_conf;
    pwr_mgmt0_t         pwr_mgmt;
    odr_range_t         gyro_conf0;
    odr_range_t         accel_conf0;
    apex_conf0_t        apex_conf0;
    apex_conf1_t        apex_conf1;
    wom_conf_t          wom_conf;
    fifo_conf1_t        fifo_conf1;
    int_src0_t          int_src0;
    int_src1_t          int_src1;
    int_src3_t          int_src3;
    int_src4_t          int_src4;    
    intf_conf0_t        intf_conf0;
    int_status_t        int_status;
    int_status2_t       int_status2;
    int_status3_t       int_status3;
    tmst_conf1_t        tmst_conf1;
    fifo_conf5_t        fifo_conf5;
    int_src6_t          int_src6;
    int_src7_t          int_src7;
    lowg_conf_t         lowg_conf;
	blk_sel_w_t         blk_sel_w;
	maadr_w_t           maadr_w;
	m_w_t               m_w;
    bitwise_t           bitwise;
    uint8_t             byte;
} icm_reg_t;

#ifdef __cplusplus
}
#endif

#endif /*__ICM42670_H__ */